#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>

typedef int DataType;

typedef struct Node
{
	DataType _data;
	struct Node* _pNext;
}Node,*pNode;

//创建新节点
pNode BuyNewNode(DataType data)
{
	pNode ptr=NULL;
	ptr=(pNode)malloc(sizeof(Node));
	if(NULL==ptr){
		assert(0);
		return NULL;
	}

	ptr->_data=data;
	ptr->_pNext=NULL;
	return ptr;
}

//头插
void ListPushFront(pNode *pHead,DataType data) 
{
	pNode newNode=NULL;
	assert(pHead);
	newNode=BuyNewNode(data);
	
	newNode->_pNext=*pHead;
	*pHead=newNode;
	
}

//头删
void ListPopFront(pNode *pHead)
{
	assert(pHead);
	if(NULL==*pHead){
		return;
	}
		
	pNode delNode=NULL;
	delNode=*pHead;
	*pHead=(*pHead)->_pNext;
	free(delNode);
}

//判空
int ListEmpty(pNode pHead)
{
	if(pHead==NULL)
		return 1;
	return 0;
}
//打印链表
void PrintList(pNode pHead)
{
	while(pHead){
		printf("%d-->",pHead->_data);
		pHead=pHead->_pNext;
	}
	printf("NULL\n");
}

//获取链接节点个数
int ListSize(pNode pHead)
{
	int size=0;
	while(pHead){
		size++;
		pHead=pHead->_pNext;
	}
	return size;
}

pNode pHead=NULL;
//互斥锁
pthread_mutex_t mutex;
//条件变量
pthread_cond_t cond1;
pthread_cond_t cond2;

//生产者
void *producer(void *arg)
{
	//向链表中插入节点
	while(1){
		//访问临界资源前先上锁

		//如果链表中已经有一个节点，就不再生产，需要在该条件变量下等待消费者
		//并且释放锁
		if(ListSize(pHead)==1){
			pthread_cond_wait(&cond2,&mutex);
		}

		//生产者生产
		ListPushFront(&pHead,5);
		printf("i product:\n");
		PrintList(pHead);
		//唤醒消费者
		//这里一定是先唤醒正在等待的消费者，在释放锁
		pthread_cond_signal(&cond1);
		pthread_mutex_unlock(&mutex);
		//这里用时间来表示优先级
		sleep(1);
	}
}

void *consumer(void *arg)
{
	while(1){
		pthread_mutex_lock(&mutex);
		if(ListEmpty(pHead)){
			pthread_cond_wait(&cond1,&mutex);
		}
		ListPopFront(&pHead);
		printf("i consumer:\n");
		PrintList(pHead);

		pthread_cond_signal(&cond2);
		pthread_mutex_unlock(&mutex);
		sleep(3);
	}
}
int main()
{
	pthread_t tid1,tid2;
	pthread_mutex_init(&mutex,NULL);
	pthread_cond_init(&cond1,NULL);
	pthread_cond_init(&cond2,NULL);

	pthread_create(&tid1,NULL,producer,NULL);
	pthread_create(&tid2,NULL,consumer,NULL);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	return 0;
}











